package com.apes.scm.masterdata.product.service;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.apes.framework.api.DomainService;
import com.apes.framework.api.SpringManager;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.plugin.cache.Cache;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.util.Arith;
import com.apes.framework.util.MapUtil;
import com.apes.scm.masterdata.party.model.PartyRole;
import com.apes.scm.masterdata.product.model.*;
import com.apes.scm.masterdata.product.repository.*;
import com.apestech.framework.util.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.data.domain.*;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StopWatch;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 功能：商品类目 Service
 *
 * @author HuJianlin
 * @create 2018-03-15 14:35
 */
@Service("categoryService")
public class CategoryService extends DomainService {

    @Autowired
    CategoryRepository categoryRepository;
    @Autowired
    ProductRepository productRepository;
    @Autowired
    CategoryDao categoryDao;
    @Autowired
    Cache cache;
    @Autowired
    CategoryTagRepository categoryTagRepository;
    @Autowired
    CategoryWorkHoursRepository categoryWorkHoursRepository;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    private final String CONST_DEFAULT_CACHENAME = "smartAccessoriesConfigCache";
    private final String CONST_CONFIG_KEY = "config";
    public Category save(SimpleRequest request) {
        Category category = request.getO(Category.class);
        addDefault(category);
        checkUnique(category);
        return categoryRepository.saveAndFlush(category);
    }

    public Category update(SimpleRequest request) {
        Category category = request.getO(Category.class);

        addDefault(category);
        checkUnique(category);

        return categoryRepository.saveAndFlush(category);
    }

    /**
     * 功能：查询
     *
     * @param request
     */
    public Page<Category> findAll(SimpleRequest request) {
        return categoryRepository.findAll(PageRequest.of(request.get("page"), request.get("size")));
    }

    public String delete(SimpleRequest request) {
        String id = request.get("id");
        Category category = categoryRepository.findOne(id);
        if (category == null) throw new RuntimeException("商品分类编码：" + request.get("id") + " 在系统中不存在。");
        categoryRepository.delete(category);
        return "删除成功！";
    }

    public Category findOne(String id) {
        return categoryRepository.findOne(id);
    }


    /**
     * 接收主数据系统同步消息
     *
     * @param request
     */
    private void receiveSave(SimpleRequest request) {
        Map map = request.getMap();
        Category category = categoryRepository.findOne(map.get("id").toString());
        if (category == null) {
            category = new Category();
            category.setId(map.get("id").toString());
        }
        category.setName(map.get("name").toString());
        if (request.getMap().containsKey("categoryId")) {
            Classify plid = SpringManager.getBean(ClassifyRepository.class).findOne((String) request.get("categoryId"));
            category.setClassify(plid);
        }

        addDefault(category);
        checkUnique(category);

        categoryRepository.save(category);
        if (categoryRepository.findAll(JpaDsl.toCriteriaByEq("name", category.getName())).size() > 1) {
            throw new RuntimeException("已存在同名配件");
        }
    }

    /***
     * 添加默认标签
     */
    private void addDefault(Category category) {
        // 判断是否存在和配件名称相同的标签
        boolean isExist = category.getCategoryTags().stream().anyMatch(categoryTag -> categoryTag.getName().equals(category.getName()));

        if (!isExist){
            CategoryTag categoryTag = new CategoryTag();
            categoryTag.setCategory(category);
            categoryTag.setName(category.getName());
            category.getCategoryTags().add(categoryTag);
        }
    }

    /***
     * 判断是否存在相同的标签
     */
    private void checkUnique(Category category){

        Map<String, List<CategoryTag>> groupByName = category.getCategoryTags()
                .stream().collect(Collectors.groupingBy(e -> e.getName()));

        Map.Entry<String, List<CategoryTag>> anyMatch = groupByName.entrySet().stream()
                .filter(entry -> entry.getValue().size() > 1).findFirst().orElse(null);

        if( anyMatch != null ) {
            throw new RuntimeException("存在相同的标签名，重复标签名为：" + anyMatch.getKey());
        }
    }

    /***
     * 商品标签查询格式化
     */
    public Page<Map> findAllFormat(SimpleRequest request) {
        Page<Category> categoryPage = request.getO(Page.class);
        List<Map> categories = new ArrayList<>();
        categoryPage.getContent().stream().forEach(
                category -> {
                    if (category.getCategoryTags().size() == 0) {
                       category.setTagName(category.getName());
                        categories.add(MapUtil.mapped(category));
                    } else {
                        category.getCategoryTags().forEach(categoryTag -> {
                            category.setTagName(categoryTag.getName());
                            categories.add(MapUtil.mapped(category));
                        });
                    }
                }
        );
        return new PageImpl<>(categories, categoryPage.getPageable(), categoryPage.getTotalElements());
    }


    /***
     * 通过关键词查询
     */

    public Page<Map> findAllByKeyword(SimpleRequest request) {
        JSONObject tempJson = request.getJO();
        String keyword = tempJson.getString("key");
        if( keyword == null ) throw new RuntimeException("查询条件不能为空");
        JSONObject param = new JSONObject();
        param.put("SIZE", request.get("size"));
        param.put("PAGE", request.get("page"));
        param.put("KEYWORD", keyword);

        // 手动拼接查询条件
        JSONArray categoryArray = categoryDao.queryCategory(param);

        List<Map> resultList = categoryArray.stream().map( item -> {
            JSONObject itemJson = (JSONObject) item;
            Map m = new HashMap();
            m.put("id", itemJson.getString("CATEGORY_ID")); //编码
            m.put("name", itemJson.getString("NAME")); //名称
            m.put("tagName", itemJson.getString("TAG_NAME")); //别名
            return m;
        }).collect(Collectors.toList());

        Pageable pageable = PageRequest.of(request.get("page"), request.get("size"));
        PageImpl<Map> pPage = new PageImpl<>(resultList, pageable, categoryArray.size() == 0 ?
                categoryArray.size() : categoryArray.getJSONObject(0).getIntValue("TOTAL"));
        return pPage;
    }


    public Map findCategoryWorkHours(SimpleRequest request){
        JSONObject tempJson = request.getJO();
        String categoryId = tempJson.getString("categoryId");
        if( categoryId == null ) throw new RuntimeException("配件ID不能为空!");
        Category category = categoryRepository.findOne(categoryId);
        if (category==null) throw new RuntimeException("没有该配件!");
        List<CategoryWorkHours> workHours = category.getCategoryWorkHoursArrayList().stream().filter(categoryWorkHours -> categoryWorkHours.getProduct()!=null).collect(Collectors.toList());
        if (workHours.size()==0) throw new RuntimeException("没有找到对应工时商品，请使用”添加工时“功能选择所需工时");
        List<Object> products = workHours.stream().map(categoryWorkHours -> {
            Product product = categoryWorkHours.getProduct();
            if (product==null) throw new RuntimeException("该配件未配置对应的工时商品，请联系门管中心对接人进行配置");
            return MapUtil.mapped(product);
        }).collect(Collectors.toList());
        List items = new ArrayList();
        for (Object product : products) {
            items.add(this.invoke("fn.service.getPrise", MapUtil.mapper("condition",product,"conditionModel", tempJson.getJSONObject("model"))));
        }

        return MapUtil.mapper("product",null,"items",items);
    }

    /***
     * 查询标准配件名称
     */

    public Object findAccessoryByKeyword(SimpleRequest request) {
        JSONObject tempJson = request.getJO();
        String keyword = tempJson.getString("key");
        if( keyword == null ) throw new RuntimeException("查询条件不能为空");
        JSONObject param = new JSONObject();
        param.put("size", request.get("size"));
        param.put("page", request.get("page"));
        String escape = escape(keyword);
        param.put("name", escape);
        Page<Category> categories = (Page<Category>) invoke("es.category.findByName", param);
        Map configCache = getSmartAccessoriesConfig();
        List<Map> collect = categories.getContent().stream().filter(category -> category != null).map(category -> {
            Map map = new HashMap();
            map.put("id", category.getId());
            map.put("name", category.getName());
            Map classifyConfig = null;
            if (category.getClassify() != null) {
                classifyConfig = (Map) configCache.get(category.getClassify().getId());
            }
            map.put("filterCondition", classifyConfig);
            if (classifyConfig != null) {
                int matchingProductConfig = (int)((Map) classifyConfig.get("smartAccessoriesConfig")).get("matchingProductConfig");
                if (matchingProductConfig == 0) {
                    map.put("queryStock", false);
                }
            }
            return map;
        }).collect(Collectors.toList());
        return new PageImpl<>(collect, categories.getPageable(), categories.getTotalElements());
    }


    // public void syncPJMC(SimpleRequest request){
    //     List<Map> list = categoryRepository.findAllTPDZ();
    //
    //     String ftpHostName = "14.23.148.134";
    //     String ftpImgPort = "8003";
    //
    //     list.forEach( item -> {
    //         JSONObject json = new JSONObject();
    //         if (Optional.ofNullable(item.get("TPLJ")).isPresent()) {
    //             String[] fileNames = item.get("TPLJ").toString().split("/");
    //             json.put("fileName", fileNames[fileNames.length-1]);
    //             json.put("size", 0);
    //             json.put("name", fileNames[fileNames.length-1]);
    //             json.put("id", "");
    //             json.put("type","image/jpeg");
    //             json.put("url", "http://"+ftpHostName+ ":" + ftpImgPort + "/" + item.get("TPLJ").toString() );
    //
    //             // 更新 category
    //             Category category = categoryRepository.findOne(item.get("CODING").toString());
    //             if (Optional.ofNullable(category).isPresent()){
    //                 JSONArray array = new JSONArray();
    //                 array.add(json);
    //                 category.setCategoryPhotos(array.toString());
    //                 categoryRepository.saveAndFlush(category);
    //             }
    //         }
    //     });
    // }

    /**
     * 关键词特殊字符转义
     * @param s
     * @return
     */
    public static String escape(String s) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            if (c == '\\' || c == '+' || c == '-' || c == '!' || c == '(' || c == ')' || c == ':'
                    || c == '^' || c == '[' || c == ']' || c == '\"' || c == '{' || c == '}' || c == '~'
                    || c == '*' || c == '?' || c == '|' || c == '&' || c == '/') {
                sb.append('\\');
            }
            sb.append(c);
        }
        return sb.toString();
    }

    // TODO 获取智选配件配置
    public Map getSmartAccessoriesConfig() {
        String CACHE_INIT_FLAG = "initFlag";
        Boolean init = (Boolean) cache.get(CONST_DEFAULT_CACHENAME, CACHE_INIT_FLAG);
        if (init == null || init == false) {
            invoke("fn.practicalFunction.smartAccessoriesConfig.cache", "");
        }

        return (Map)cache.get(CONST_DEFAULT_CACHENAME, CONST_CONFIG_KEY);
    }

    /**
     * 配件名称标签、关联工时导入
     * @param request
     */
    public Map uploadingCategoryTag(SimpleRequest request) {
        List notCategory = Collections.synchronizedList(new ArrayList());

        //Excel信息
        JSONObject importData = request.get("importData");
        //判断导入类别 tag=俗称导入  work=工时导入
        String impl = request.getJO().getJSONObject("model").getString("impl");
        Map map = new HashMap();
        //查找所有配件ID
        List<String> categoryAllId = categoryRepository.findAllId();
        for (Map.Entry<String, Object> entry : importData.entrySet()) {
            Object v = entry.getValue();
            JSONArray importArray = (JSONArray) v;
            if ("tag".equals(impl)) {
                if (((JSONArray) importArray.get(0)).size() != 3) throw new RuntimeException("导入模板错误，请检查文件并重新上传！");
                importArray.parallelStream().forEach(item -> {
                    JSONArray iValueArray = (JSONArray) item;
                    //跳过首行
                    if ("配件ID".equals(iValueArray.getString(0)) && "配件名称".equals(iValueArray.getString(1))) return ;
                    //数据导入与校验
                    this.categoryTagImpl(iValueArray,categoryAllId,notCategory);
                });
                map.put("notCategory", notCategory);
                map.put("loserSize", notCategory.size());
                map.put("tag", "tag");
                //用Redis，缓存进度条和结果
                stringRedisTemplate.opsForValue().set("not_CategoryTag" + request.getPersonId(), notCategory.toString(), 5, TimeUnit.MINUTES);
                //stringRedisTemplate.opsForValue().set("successfulTag" + request.getPersonId(), "" + notCategory.size(), 4, TimeUnit.MINUTES);
                stringRedisTemplate.opsForValue().set("failingTag" + request.getPersonId(), "" + notCategory.size(), 4, TimeUnit.MINUTES);
                return map;

            } else {
                if (((JSONArray) importArray.get(0)).size() != 4) throw new RuntimeException("导入模板错误，请检查文件并重新上传！");
                importArray.parallelStream().forEach(item -> {
                    JSONArray iValueArray = (JSONArray) item;
                    //跳过首行
                    if ("配件ID".equals(iValueArray.getString(0)) && "配件名称".equals(iValueArray.getString(1))) return ;
                    this.categoryWorkHoursImpl(iValueArray,categoryAllId,notCategory);
                });
                map.put("notCategory", notCategory);
                map.put("loserSize", notCategory.size());
                map.put("work", "work");
                //用Redis，缓存进度条和结果
                stringRedisTemplate.opsForValue().set("not_CategoryWork" + request.getPersonId(), notCategory.toString(), 5, TimeUnit.MINUTES);
                //用于结果页面展示
               // stringRedisTemplate.opsForValue().set("successfulWork" + request.getPersonId(), "" + notCategory.size(), 4, TimeUnit.MINUTES);
                stringRedisTemplate.opsForValue().set("failingWork" + request.getPersonId(), "" + notCategory.size(), 4, TimeUnit.MINUTES);
                return map;
            }

        }
        return null;
    }

    /**
     * 下载失败结果
     *
     * @param request
     * @return
     */
    public Map productDetail(SimpleRequest request) {
       JSONObject jo =  request.getJO();
       String not = "not_CategoryTag";
       if("work".equals(jo.getString("impl"))){
           not = "not_CategoryWork";
       }
        String productStocks = stringRedisTemplate.opsForValue().get(not + request.getPersonId());
        JSONArray objects = JSONArray.parseArray(productStocks);
        if(objects==null)return MapUtil.mapper("content", null, "total", 0, "pages",0);
        assert objects != null;
        stringRedisTemplate.delete("not" + request.getPersonId());
        return MapUtil.mapper("content", new ArrayList<>(objects), "total", objects.size(), "pages", request.get("page"));
    }

    /**
     * 俗称导入
     * @param iValueArray
     * @param categoryAllId
     * @param notCategory
     */
    public void categoryTagImpl(JSONArray iValueArray,List<String> categoryAllId,List notCategory){
        //跳过列名和导入规则行
        if (StringUtil.isNotEmpty(iValueArray.getString(0)) && StringUtil.isNotEmpty(iValueArray.getString(2)) && categoryAllId.contains(iValueArray.getString(0))) {
            Category category = categoryRepository.findOne(iValueArray.getString(0));
            List<String> categoryTagNameMap = categoryTagRepository.findByCategory(category.getId());
            //判断俗称是否重复
            boolean isName = categoryTagNameMap.contains(iValueArray.getString(2));
            if (!isName) {
                CategoryTag categoryTag = new CategoryTag();
                categoryTag.setCategory(category);
                categoryTag.setName(iValueArray.getString(2));
                categoryTagRepository.saveAndFlush(categoryTag);
            } else {
                //导入失败回写
                notCategory.add(categoryTagfailed(iValueArray, categoryAllId, categoryTagNameMap));
            }
        } else {
            //导入失败回写
            notCategory.add(categoryTagfailed(iValueArray, categoryAllId, null));
        }
    }

    /**
     * 工时导入
     * @param iValueArray
     * @param categoryAllId
     * @param notCategory
     */
    public void categoryWorkHoursImpl(JSONArray iValueArray,List<String> categoryAllId,List notCategory){
        Product product = null;
        if(StringUtil.isNotEmpty(iValueArray.getString(2))) {
            product = productRepository.findOne(iValueArray.getString(2));
        }
        //判断志是否为空
        if (StringUtil.isNotEmpty(iValueArray.getString(0)) && StringUtil.isNotEmpty(iValueArray.getString(2)) && categoryAllId.contains(iValueArray.getString(0)) && product!=null) {
            Category category = categoryRepository.findOne(iValueArray.getString(0));
            List<String> categoryWorkHoursIdMap = categoryWorkHoursRepository.findByCategory(category.getId());
            //判断商品是否重复
            boolean isProduct = categoryWorkHoursIdMap.contains(iValueArray.getString(2));
            if (!isProduct) {
                CategoryWorkHours categoryWorkHours = new CategoryWorkHours();
                categoryWorkHours.setCategoryId(category);
                categoryWorkHours.setProduct(product);
                categoryWorkHoursRepository.saveAndFlush(categoryWorkHours);
            } else {
                //导入失败回写
                notCategory.add(categoryWorkHoursfailed(iValueArray, categoryAllId, product));
            }
        } else {
            //导入失败回写
            notCategory.add(categoryWorkHoursfailed(iValueArray, categoryAllId, null));
        }
    }

        /**
         * 俗称导入校验
         * @param array
         * @param allID
         * @param allName
         * @return
         */
        public JSONObject categoryTagfailed(JSONArray array,List<String> allID,List<String> allName){
            JSONObject notProduct = new JSONObject();
            StringBuilder cause = new StringBuilder();
            for (int i = 0; i < array.size(); i++) {
                switch (i) {
                    case 0: {
                        if (Objects.isNull(array.getString(i)) || !allID.contains(array.getString(i)))
                            cause.append("配件ID不存在;");
                        notProduct.put("ID", array.getString(i));
                        break;
                    }
                    case 1: {
//                    if (Objects.isNull(array.getString(i))) cause.append("配件名称不能为空;");
                        notProduct.put("categoryName", array.getString(i));
                        break;
                    }
                    case 2: {
                        if (Objects.isNull(array.getString(i))) cause.append("俗称不能为空;");
                        if (allName != null && allName.contains(array.getString(i))) cause.append("俗称重复;");
                        notProduct.put("name", array.getString(i));
                        break;
                    }

                }
            }
            notProduct.put("cause", cause.toString());
            return notProduct;
        }


        /**
         * 工时导入校验
         * @param array
         * @param allID
         * @param product
         * @return
         */
        public JSONObject categoryWorkHoursfailed (JSONArray array, List <String> allID, Product product){
            JSONObject notProduct = new JSONObject();
            StringBuilder cause = new StringBuilder();
            for (int i = 0; i < array.size(); i++) {
                switch (i) {
                    case 0: {
                        if (Objects.isNull(array.getString(i)) || !allID.contains(array.getString(i)))
                            cause.append("配件ID不存在;");
                        notProduct.put("ID", array.getString(i));
                        break;
                    }
                    case 1: {
                        notProduct.put("categoryName", array.getString(i));
                        break;
                    }
                    case 2: {
                        if (Objects.isNull(array.getString(i)) || product==null) cause.append("商品ID不存在;");
                        if (!Objects.isNull(array.getString(i)) && product!=null) cause.append("商品重复;");
                        notProduct.put(" productId", array.getString(i));
                        break;
                    }
                    case 3: {
                        notProduct.put(" productName", array.getString(i));
                        break;
                    }

                }
            }
            notProduct.put("cause", cause.toString());
            return notProduct;
        }


    /**
     * 下载
     *
     * @param request
     * @return
     */
    public Map download(SimpleRequest request) {
        JSONObject jo = request.getJO();
        if("俗称数据".equals(jo.getString("queryname"))){
            Page<CategoryTag> page = categoryTagRepository.findAll(JpaDsl.toCriteriaIgnoreNull(),
                    PageRequest.of(request.get("page"), request.get("size"), Sort.by(Sort.Direction.DESC, "id")));
            return MapUtil.mapper("content", page.getContent(), "total", page.getTotalElements(), "pages", page.getTotalPages(), "page", request.get("page"));
        }
        if("工时数据".equals(jo.getString("queryname"))){
            Page<CategoryWorkHours> page = categoryWorkHoursRepository.findAll(JpaDsl.toCriteriaIgnoreNull(),
                    PageRequest.of(request.get("page"), request.get("size"), Sort.by(Sort.Direction.DESC, "id")));
            return MapUtil.mapper("content", page.getContent(), "total", page.getTotalElements(), "pages", page.getTotalPages(), "page", request.get("page"));
        }
       return new HashMap();
    }

}
